package com.mathdroid.gui.main.advertising;

import java.awt.Cursor;
import java.awt.Dimension;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Insets;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.io.IOException;
import java.util.LinkedList;

import javax.swing.JButton;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JSpinner;
import javax.swing.SpinnerModel;
import javax.swing.SpinnerNumberModel;
import javax.swing.SwingWorker;

import com.mathdroid.gui.ImageLoader;
import com.mathdroid.model.Model;

/**
 * This is a SwingWorker thread, that contains a panel with an advertising 
 * banner and a "simulate" button. The panel is added to the bottom right
 * split pane of the main frame.
 */
public final class Advertising extends SwingWorker<Void, Void> {

	/**
	 * Default UID.
	 */
	private static final long serialVersionUID = 1L;

	/**
	 * The spacing between UI components.
	 */
	private static final int SPACING = 10;
	
	/**
	 * The height of the simulate button.
	 */
	private static final int BUTTON_HEIGHT = 35;
	
	/**
	 * The width of the JSpinner.
	 */
	private static final int SPINNER_WIDTH = 80;

	/**
	 * One second is 1000 milliseconds.
	 */
	private static final int SEC_IN_MILLIES = 1000;
	
	/**
	 * Image loader.
	 */
	private final ImageLoader il = new ImageLoader();
	
	/**
	 * The button to start a new simulations.
	 */
	private final JButton simulate = new JButton("Simulate");
	
	/**
	 * The spinner to define the number of iterations per simulation.
	 */
	private final JSpinner iterations = new JSpinner();
	
	/**
	 * The label that contains the advertising image.
	 */
	private final JLabel ad = new JLabel();
	
	/**
	 * Constraints for this UI components.
	 */
	private final GridBagConstraints c = new GridBagConstraints();
	
	/**
	 * A list of advertising.
	 */
	private final LinkedList<Ad> ads = new LinkedList<Ad>();
	
	/**
	 * The index of the current shown advertising.
	 */
	private int currentAd = 0;
	
	/**
	 * The content panel.
	 */
	private JPanel p = new JPanel();

	/**
	 * Create a new advertising SwingWorker thread. Call the "getPanel()"
	 * method to get the content panel.
	 */
	public Advertising() {
		super();
		this.p.setLayout(new GridBagLayout());
		this.p.setPreferredSize(new Dimension(500, 0));

		this.buildAds();
		this.nextAd();
		
		this.buildAd();
		this.buildSpinner();
		this.buildButton();
	}
	
	/**
	 * Build the iterations spinner.
	 */
	private void buildSpinner() {
		final int min = 100;
		final int step = 100;
		final int start = 1000;
		final int max = 10000000;
		
		SpinnerModel model = new SpinnerNumberModel(start, min, max, step);
		this.iterations.setModel(model);
		
		this.c.insets = new Insets(0, SPACING, SPACING, SPACING);
		this.c.gridx = 0;
		this.c.gridy = 1;
		this.c.gridwidth = 1;
		
		this.iterations.setPreferredSize(
				new Dimension(SPINNER_WIDTH, BUTTON_HEIGHT));
		
		this.iterations.setToolTipText("Iterations. More iterations increase "
				+ "the accuracy.");
		
		this.p.add(this.iterations, this.c);
		
	}

	/**
	 * Build the list of advertising.
	 */
	private void buildAds() {
		this.ads.add(new Ad(10, this.il.getAdImage("dummy"), 
				"http://www.google.com#1"));
		this.ads.add(new Ad(10, this.il.getAdImage("dummy2"), 
				"http://www.google.com#2"));
	}

	/**
	 * Refresh the UI to show the next advertising. This is a loop.
	 */
	private void nextAd() {
		this.currentAd = (this.currentAd + 1) % this.ads.size();
		this.simulate.setPreferredSize(new Dimension(
				this.ads.get(this.currentAd).getImage().getIconWidth() 
				- SPINNER_WIDTH - SPACING, 
				BUTTON_HEIGHT));
		this.ad.setIcon(this.ads.get(this.currentAd).getImage());
		this.ad.setToolTipText(
				this.ads.get(this.currentAd).getUri().toString());
	}

	/**
	 * Build the "simulate" button.
	 */
	private void buildButton() {
		this.c.insets = new Insets(0, 0, SPACING, SPACING);
		this.c.gridx = 1;
		this.c.gridy = 1;
		this.c.gridwidth = 1;
		this.simulate.setIcon(this.il.getImage("chart_column_big"));
		
		this.simulate.addActionListener(new ActionListener() {
			@Override
			public void actionPerformed(final ActionEvent e) {
				Model.simulate(((Integer) iterations.getValue()).intValue());
			}
		});
		
		this.p.add(this.simulate, this.c);
	}
	
	/**
	 * Build the advertising label.
	 */
	private void buildAd() {
		this.c.insets = new Insets(SPACING, SPACING, SPACING, SPACING);
		this.c.gridx = 0;
		this.c.gridy = 0;
		this.c.gridwidth = 2;
		
		this.ad.addMouseListener(new MouseAdapter() {
			@Override
			public void mouseEntered(final MouseEvent e) {
				p.setCursor(new Cursor(Cursor.HAND_CURSOR));
			}
			
			@Override
			public void mouseExited(final MouseEvent e) {
				p.setCursor(new Cursor(Cursor.DEFAULT_CURSOR));
			}
			
			@Override
			public void mouseClicked(final MouseEvent e) {
				try {
					java.awt.Desktop.getDesktop()
					.browse(ads.get(currentAd).getUri());
				} catch (IOException e1) {
					e1.printStackTrace();
				}
			}
		});
		
		this.p.add(this.ad, this.c);
	}
	
	/**
	 * @return The content panel.
	 */
	public JPanel getPanel() {
		return this.p;
	}

	@Override
	protected Void doInBackground() throws Exception {
		
		while (!this.isCancelled()) {
			Thread.sleep(this.ads.get(
					this.currentAd).getSeconds() * SEC_IN_MILLIES);
			this.nextAd();
		}
		
		return null;
	}
}
